// Copyright (c) 2022 Presto Labs Pte. Ltd.
// Author: daniel

#pragma once

#include <memory>
#include <string>
#include <unordered_map>
#include <vector>

#include "coin2/exchange/base/order/order.h"
#include "coin2/exchange/order/bybit.pb.h"

namespace coin2::exchange::bybit_common::api_util {
class BybitRateTracker;
}

namespace coin2::exchange::bybit_futures::api_order_v3 {

class BybitFuturesNativePrivateClient : public coin2::exchange::base::order::NativePrivateClient {
 public:
  using RestParams = coin2::exchange::order::BybitRestParams;
  using NativeClientConfig = coin2::exchange::order::OrderConnectionConfig;
  using ActionType = coin2::exchange::base::order::NativePrivateClient::ActionType;
  using BybitRateTracker = coin2::exchange::bybit_common::api_util::BybitRateTracker;

 public:
  std::shared_ptr<AsioHttpContext> SubmitOrderExecution(const OrderExecutionProto& order);
  std::shared_ptr<AsioHttpContext> SubmitRestQuery(const RestQueryProto& query);

 public:
  explicit BybitFuturesNativePrivateClient(
      const MarketExchangeApi& mea,
      const NativeClientConfig& config);

  void Prepare() override;

  std::shared_ptr<AsioHttpContext> QueryBalance();
  std::shared_ptr<AsioHttpContext> QueryPosition(const RestParams& params);
  std::shared_ptr<AsioHttpContext> QueryOpenOrders(const RestParams& params);
  std::shared_ptr<AsioHttpContext> QueryDoneOrders(const RestParams& params);
  std::shared_ptr<AsioHttpContext> QueryFills(const RestParams& params);
  std::shared_ptr<AsioHttpContext> PlaceOrder(
      const RestParams& params,
      const OrderSpec& order_spec);
  std::shared_ptr<AsioHttpContext> AmendOrder(const RestParams& params);
  std::shared_ptr<AsioHttpContext> CancelSingleOrder(const RestParams& params);

  std::shared_ptr<AsioHttpContext> PlaceOrderNorm(const OrderExecution&) override;
  std::shared_ptr<AsioHttpContext> CancelOrderNorm(const OrderExecution&) override;

  RestParams GetRestOrderParams(const OrderSpec& order_spec, int64_t proc_order_id);
  RestParams GetRestCancelParams(const IOrderContext& order_context);

  bool HasEnoughRateLimit(
      int64_t ts,
      ActionType action_type,
      const std::string& endpoint,
      const std::string& bind_ip) const;
  void Push(
      int32_t num_reqs,
      int64_t ts,
      ActionType action_type,
      const std::string& path,
      const std::string& bind_ip);

 private:
  BybitRateTracker* local_rate_tracker_;

  const std::string endpoint_account_balance_ = "/contract/v3/private/account/wallet/balance";
  const std::string endpoint_account_position_ = "/contract/v3/private/position/list";
  const std::string endpoint_query_open_order_ = "/contract/v3/private/order/unfilled-orders";
  const std::string endpoint_query_done_order_ = "/contract/v3/private/order/list";
  const std::string endpoint_query_fill_order_ = "/contract/v3/private/execution/list";
  const std::string endpoint_submit_order_ = "/contract/v3/private/order/create";
  const std::string endpoint_amend_order_ = "/contract/v3/private/order/replace";
  const std::string endpoint_cancel_order_ = "/contract/v3/private/order/cancel";

  const std::vector<std::string> http_get_endpoints_ = {
      endpoint_account_balance_,
      endpoint_account_position_,
      endpoint_query_open_order_,
      endpoint_query_done_order_,
      endpoint_query_fill_order_};
  const std::vector<std::string> http_post_endpoints_ = {
      endpoint_submit_order_,
      endpoint_amend_order_,
      endpoint_cancel_order_};
};

}  // namespace coin2::exchange::bybit_futures::api_order_v3
